package com.pi.pro.xcmg.am.was.fac.handler;


import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.pi.common.CodesConstants;
import com.pi.common.utils.StringUtils;
import com.pi.pro.xcmg.am.common.XcmgAmConstants;
import com.pi.pro.xcmg.am.common.XcmgAmSupport;
import com.pi.pro.xcmg.am.common.vo.act.MoveChangeDto;
import com.pi.pro.xcmg.am.was.edi.wcs.dto.CommonResultData;
import com.pi.pro.xcmg.am.was.fac.service.WasCustomWorkService;
import com.pi.pro.xcmg.am.was.fac.service.WcsCustomWorkService;
import com.pi.sys.service.AlertService;
import com.pi.wms.common.WmsConstants;
import com.pi.wms.dto.act.PutawayActionDto;
import com.pi.wms.dto.act.PutawayLineDto;
import com.pi.wms.dto.act.TaskActionDto;
import com.pi.wms.dto.base.LocationLineDto;
import com.pi.wms.entity.TwaInventoryDetails;
import com.pi.wms.entity.TwmBasLocation;
import com.pi.wms.entity.TwtActPalletizeList;
import com.pi.wms.entity.TwtActTaskList;
import com.pi.wms.fac.LocationResolver;
import com.pi.wms.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * 上线扫描-码盘/
 */
@Slf4j
@Component
public class LineAcceptPalletizeDelegateHandler extends BaseDelegateHandler  {


    @Autowired
    private DivisionService divisionService;

    @Autowired
    private InventoryDetailsService inventoryService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private PalletizeService palletizeService;

    @Autowired
    private PutawayService putawayService;

    @Autowired
    private LogisticsSeqService seqService;

    @Autowired
    private AlertService alertService;

    @Autowired
    private LocationResolver locationResolver;

    @Autowired
    private WasCustomWorkService customWorkService;

    @Autowired
    private WcsCustomWorkService wcsCustomWorkService;

    //
    private boolean createNewReturnTask=false;

    private Map<Long, String> lastCheckoutContainers=new HashMap<>();

    private Cache<String, LocationLineDto> locationCache= CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).build();
    private Cache<String, String> containerCache= CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build();
    private Cache<String, String> containerErrorCache= CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build();
    private Cache<String, String> alarmCache= CacheBuilder.newBuilder().expireAfterWrite(20, TimeUnit.MINUTES).build();
    //
    public String perform(MoveChangeDto moveChangeDto, TaskActionDto actionDto){
        String m="";
        /**
         * 1. check
         */
        m= XcmgAmSupport.check(moveChangeDto);
        if (!StringUtils.isNullOrBlank(m)){
            return m;
        }
        String containNumber=moveChangeDto.getContainerNumber().trim();
        String batchNumber=moveChangeDto.getRequestNumber();
        String lockloc=null;
        boolean returntaskflag = false;
        String returnerror=null;
        String keyvalue= StringUtils.ifNullOrBlank(moveChangeDto.getDivisionCode(), CodesConstants.COMMON_WILDCARD)
                         +":" + moveChangeDto.getLocationCode()+"/"+moveChangeDto.getContainerNumber();
        CommonResultData wcsResultData=null;

        //cache
        lockloc = containerCache.getIfPresent(containNumber);
        if (!StringUtils.isNullOrBlank(lockloc)){
            m="";
            return m;
        }

        lockloc = containerErrorCache.getIfPresent(keyvalue);
        if (!StringUtils.isNullOrBlank(lockloc)){
            m=lockloc;
            return m;
        }
        //
        Long divisionid= XcmgAmConstants.DIVISION_WH101_ID;
        LocationLineDto fromlocation=this.locationCache.getIfPresent(moveChangeDto.getLocationCode());
        if (fromlocation==null){
            if (!StringUtils.isNullOrBlank(moveChangeDto.getDivisionCode())){
                divisionid=this.divisionService.retrieve(moveChangeDto.getDivisionCode());
            }
            fromlocation=this.locationResolver.lookup(divisionid, moveChangeDto.getLocationCode());
            this.locationCache.put(moveChangeDto.getLocationCode(),fromlocation);
        }
        if (fromlocation!=null){
            divisionid=fromlocation.getDivisionId();
        }

        /**
         m = this.mock(requestData);
         if (!StringUtils.isNullOrBlank(m)){
         return m;
         }
         **/

        /**
         * 2. move-allocator
         */
        m=this.checkAndLoad(moveChangeDto);
        if (!StringUtils.isNullOrBlank(m)){
            returntaskflag = true;
            returnerror=m;
        }

        /**
         * 2. 209-空料箱-补充
         */
        List<TwtActTaskList> tasks=null;
        tasks=new ArrayList<>();
        /**
         if (this.moveAllocator!=null){
             tasks=this.moveAllocator.allocate(requestData.getRequestNumber(),allocationDto,allocationActionDto);
             if ((tasks==null)||(tasks.size()==0)){
             m="未能正确创建入库任务,请联系系统管理员.";
             return m;
         }
         }
         **/
        if ((!returntaskflag) && (StringUtils.isNullOrBlank(m))) {
            m = this.palletizeAllocate(containNumber, moveChangeDto, batchNumber, fromlocation, actionDto);
        }
        //
        if (!StringUtils.isNullOrBlank(m)){
            m=XcmgAmConstants.RESULT_CODE_EDI_WARN_FEEDBACK+"/"+"创建入库任务失败,"+m;
            returntaskflag=true;
            returnerror=m;
            this.createReturnTask(moveChangeDto, fromlocation, actionDto, m);
            this.containerErrorCache.put(keyvalue, m);
        }

        //
        if ((tasks==null) || (tasks.size()<=0)){
            if (!returntaskflag) {
                tasks = this.taskService.queryWorkingTasks(WmsConstants.TASK_TYPE_PUTAWAY, containNumber);
            }else {
                if (this.createNewReturnTask){
                    tasks=this.taskService.queryWorkingTasks(WmsConstants.TASK_TYPE_MOVE, containNumber);
                }else {
                    return m;
                }
            }
        }
        if (tasks==null){
            m=XcmgAmConstants.RESULT_CODE_EDI_WARN_FEEDBACK+"/"+"未能创建入库任务.托盘码:"+containNumber;
            returnerror=m;
            this.containerErrorCache.put(keyvalue, m);
            return m;
        }

        //SENDTI-WCS
        wcsResultData = this.wcsCustomWorkService.execute(tasks, actionDto);

        //
        this.containerCache.put(containNumber, tasks.get(0).getNumber());
        this.containerErrorCache.invalidate(keyvalue);
        this.lastCheckoutContainers.put(fromlocation.getLocationId(), containNumber);



        /**
         * 3. release
         */
        //release

        /**
         * 5. send
         */

        /**
         * 6. update-task
         */
        if (!returntaskflag) {
            m = this.customWorkService.changeTaskStatus(tasks, WmsConstants.TASK_STATUS_PULLED_DOWN, "", "LINE/" + fromlocation.getLocationCode());
        }else {
            if (this.createNewReturnTask) {
                m = this.customWorkService.changeTaskStatus(tasks, WmsConstants.TASK_STATUS_PULLED_DOWN, returnerror, "LINE/" + fromlocation.getLocationCode());
            }
        }

        /**
         * 7. update ASN-notes
         */
        Long docid=WorkDataHolders.get(divisionid).takeAsnByPalletContainnumber(containNumber);
        if (docid==null){
            docid=moveChangeDto.getRefPalletizes().get(0).getDocumentId();
        }
        m = this.customWorkService.changeAsnDeliveryStatus(divisionid, docid, containNumber, moveChangeDto.getWeightValue(), WmsConstants.TASK_STATUS_EDI_WORKING, "LINE/"+fromlocation.getLocationCode());

        return m;
    }


    private String check(MoveChangeDto moveChangeDto){
        String m="";
        String containNumber=moveChangeDto.getContainerNumber();
        if (StringUtils.isNullOrBlank(containNumber)){
            m="托盘码为空";
            return m;
        }
        List<TwtActPalletizeList> pals=this.palletizeService.findByContainNumber(containNumber);
        if ((pals==null) || (pals.size()==0)){
            m="找不到码盘数据,请确认已经扫描码盘.托盘码:"+containNumber;
            return m;
        }

        List<TwtActTaskList> tasks=this.taskService.queryWorkingTasks("",containNumber);
        if ((tasks!=null) && (tasks.size()>0)){
            m="托盘任务已经存在,请确认.托盘码:"+containNumber;
            return m;
        }
        //TODO:HU/202504
        /**
        List<TwaInventoryDetails> storages=this.inventoryService.findByContainNumber(containNumber);
        if ((storages==null) || (storages.size()==0)){
            m="找不到有效库存,无法上架.箱码:"+moveChangeDto.getContainerNumber();
            return m;
        }
        if (moveChangeDto.getRefStorages()==null){
            moveChangeDto.setRefStorages(new ArrayList<>());
        }
        moveChangeDto.getRefStorages().clear();
        moveChangeDto.getRefStorages().addAll(storages);

        //
        Long locationid=null;
        for (TwaInventoryDetails storage:storages){
            if (storage==null){
                continue;
            }
            if (locationid==null){
                locationid=storage.getLocId();
            }
            if (!locationid.equals(storage.getLocId())){
                m="库存数据异常:库存库位不一致,箱码:"+moveChangeDto.getContainerNumber();
                return m;
            }
            if ((storage.getQtyAllocated()!=null) && (storage.getQtyAllocated().compareTo(BigDecimal.ZERO))>0){
                m="存在待拣货数据,不能上架回库,箱码:"+moveChangeDto.getContainerNumber();
                return m;
            }
        }
        if (locationid==null){
            m="库存数据异常:库存库位缺失,箱码:"+moveChangeDto.getContainerNumber();
            return m;
        }
        LocationLineDto locationDto = this.locationResolver.lookup(locationid);
        if (locationDto==null){
            m="库存数据异常:库位主数据缺失,箱码:"+moveChangeDto.getContainerNumber();
            return m;
        }
        if (WmsConstants.LOCATION_TYPE_BIN.equalsIgnoreCase(locationDto.getLocationType())) {
            m="库存已经在库:箱码:"+moveChangeDto.getContainerNumber()+",库位:"+locationDto.getLocationCode();
            return m;
        }
         **/
        return m;
    }

    private String checkAndLoad(MoveChangeDto moveChangeDto){
        String m="";
        String containNumber=moveChangeDto.getContainerNumber();
        if (StringUtils.isNullOrBlank(containNumber)){
            m="托盘码为空";
            return m;
        }
        List<TwtActPalletizeList> pals=this.palletizeService.findByContainNumber(containNumber);
        if ((pals==null) || (pals.size()==0)){
            m="找不到码盘数据,请确认已经扫描码盘.托盘码:"+containNumber;
            return m;
        }

        List<TwtActTaskList> tasks=this.taskService.queryWorkingTasks("",containNumber);
        if ((tasks!=null) && (tasks.size()>0)){
            m="托盘任务已经存在,请确认.托盘码:"+containNumber;
            return m;
        }
        LocationLineDto loc=null;
        List<TwaInventoryDetails> storages=this.inventoryService.findByContainNumber(containNumber);
        if ((storages!=null) && (storages.size()>0)){
            for (TwaInventoryDetails d:storages){
                if (d==null){
                    continue;
                }
                loc=this.locationResolver.lookup(d.getLocId());
                if (WmsConstants.LOCATION_TYPE_BIN.equalsIgnoreCase(loc.getLocationType())){
                    m="托盘已经在库,并且存放了产品,请确认.托盘码:"+containNumber;
                    return m;
                }
            }
        }


        //
        moveChangeDto.setRefPalletizes(pals);
        return m;
    }

    private String palletizeAllocate(String containNumber, MoveChangeDto moveChangeDto, String batchNumber, LocationLineDto fromLocation, TaskActionDto actionDto){
        String m="";

        //1. check
        if ((moveChangeDto.getRefPalletizes()==null) || (moveChangeDto.getRefPalletizes().size()==0)){
            m="not palleized.container:"+containNumber;
            return m;
        }
        // TwaInventoryDetails storage=moveChangeDto.getRefStorages().get(0);
        TwtActPalletizeList pal=moveChangeDto.getRefPalletizes().get(0);

        //
        PutawayLineDto dataDto = new PutawayLineDto();
        this.fill(pal,dataDto,fromLocation);
        PutawayActionDto paActionDto = new PutawayActionDto();
        this.fill(paActionDto,moveChangeDto,actionDto,pal,fromLocation);

        //TODO://HU:202410
        //1. 同巷道,批量作业(小车背篓)
        //2. 巷道均衡
        //3. 深浅库位
        TwmBasLocation paLocation = this.putawayService.calculate(batchNumber,fromLocation.getDivisionId(),
                XcmgAmConstants.PA_CALCULATOR_NAME_SLOC_PA_SEQ_CALCULATOR, dataDto, paActionDto);
        if (paLocation==null){
            m="cant found putaway location.";
            return m;
        }
        //3. generate
        String bulkknumber="";
        if ((!StringUtils.isNullOrBlank(paActionDto.getResultData()))
                && (paActionDto.getResultData().startsWith("#"))){
            bulkknumber = paActionDto.getResultData().trim();
        }
        //m=this.generate(moveChangeDto.getRefStorages(), fromLocation, paLocation, batchNumber, moveChangeDto, null, bulkknumber, actionDto);
        m=this.generateByPalletize(moveChangeDto.getRefPalletizes(), fromLocation, paLocation, batchNumber, moveChangeDto, null, bulkknumber, actionDto);

        return m;
    }

    private void fill(PutawayActionDto paActionDto, MoveChangeDto moveChangeDto, TaskActionDto actionDto, TwaInventoryDetails storage, LocationLineDto fromLocation){
        if (paActionDto==null){
            return;
        }
        if (moveChangeDto!=null){
            paActionDto.setCheckHeight(moveChangeDto.getHeightValue());
            paActionDto.setCheckLength(moveChangeDto.getLengthValue());
        }
        if (storage!=null){
            paActionDto.setCheckMaterialId(storage.getMaterialId());
            paActionDto.setCheckLotnoId(storage.getLotnoId());
        }
        if (actionDto!=null){
            paActionDto.setWorker(actionDto.getWorker());
        }
        if ((fromLocation!=null) && (fromLocation.getDivisionId()!=null)){
            paActionDto.setCheckDivisionId(fromLocation.getDivisionId());
        }
        paActionDto.setCheckZoneIds(XcmgAmConstants.asrsZoneIds);
    }

    private void fill(PutawayActionDto paActionDto, MoveChangeDto moveChangeDto, TaskActionDto actionDto, TwtActPalletizeList palletize, LocationLineDto fromLocation){
        if (paActionDto==null){
            return;
        }
        if (moveChangeDto!=null){
            paActionDto.setCheckHeight(moveChangeDto.getHeightValue());
            paActionDto.setCheckLength(moveChangeDto.getLengthValue());
        }
        if (palletize!=null){
            paActionDto.setCheckMaterialId(palletize.getMaterialId());
            //paActionDto.setCheckLotnoId(palletize.getLotnoId());
        }
        if (actionDto!=null){
            paActionDto.setWorker(actionDto.getWorker());
        }
        if ((fromLocation!=null) && (fromLocation.getDivisionId()!=null)){
            paActionDto.setCheckDivisionId(fromLocation.getDivisionId());
        }
        paActionDto.setCheckZoneIds(XcmgAmConstants.asrsZoneIds);
    }

    private String createReturnTask(MoveChangeDto moveChangeDto, LocationLineDto fromLocation, TaskActionDto actionDto, String errorMessage){
        String m="";
        if (fromLocation==null){
            m="source location is null";
            return m;
        }
        TwtActTaskList task=null;
        String returnloccode=null;
        LocationLineDto returnloc=null;
        String taskNumber=null;
        String flag=CodesConstants.COMMON_FLAG_NO;
        if (this.createNewReturnTask){
            taskNumber=seqService.next(WmsConstants.SEQUENCE_NAME_ACT_TASK);
            returnloccode= XcmgAmConstants.retrunLocationMap.get(fromLocation.getLocationCode());
            if (StringUtils.isNullOrBlank(returnloccode)){
                m="source location's map is null";
                return m;
            }
            try{
                returnloc=this.locationResolver.lookup(fromLocation.getDivisionId(), returnloccode);
                if (returnloc!=null){
                    task = XcmgAmSupport.createReturnTask(taskNumber, moveChangeDto,actionDto,fromLocation,returnloc,errorMessage);
                    if (task!=null){
                        this.taskService.save(task);
                    }
                }
            }catch (Exception e){
                m="创建回退任务失败:"+e.getMessage();
            }
            if ((returnloc==null) && (StringUtils.isNullOrBlank(m))){
                m="未正确设置回退库位.源库位:"+fromLocation.getLocationCode();
            }
        }
        flag=this.alarmCache.getIfPresent(moveChangeDto.getLocationCode());
        if   ((flag==null) || (!CodesConstants.COMMON_FLAG_YES.equalsIgnoreCase(flag))){
            alertService.publishAlarm(CodesConstants.SYSTEM_WMS, "MOVE", moveChangeDto.getLocationCode(), moveChangeDto.getContainerNumber(), errorMessage, 1L, false, "ReceiveRequest", null, "", CodesConstants.COMMON_HOLD_STATUS_CLOSED,"");
            this.alarmCache.put(moveChangeDto.getLocationCode(),CodesConstants.COMMON_FLAG_YES);
        }
        return m;
    }

}
